package com.zxiw.zxedu.recyclerview

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.collection.SparseArrayCompat
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.google.android.material.appbar.AppBarLayout
import com.zxiw.zxedu.recyclerview.adapter.BH
import com.zxiw.zxedu.recyclerview.listener.AppBarStateChangeListener


/**
 * @author zhangxiaoming
 * @date 2023/8/17
 * @description <p>描述:自定义带有刷新控制的XRecyclerView<br/></p>
 * * <p>
 * setArrowImageView(int): //设置下拉刷新的箭头<br/>
 * setEmptyView(View)://没有数据时也可以设置空view<br/>
 * setFootView(View): //添加尾部view<br/>
 * setLoadingListener(LoadingListener): void<br/>
 * setLoadingMoreEnabled(boolean): //是否可以加载更多<br/>
 * setLoadingMoreProgressStyle(int): //设置加载更多动画样式<br/>
 * setNoMore(boolean): //没有更多数据<br/>
 * setPullRefreshEnabled(boolean): //是否可以上拉刷新<br/>
 * setRefreshHeader(ArrowRefreshHeader): void<br/>
 * setRefreshProgressStyle(int): //设置刷新动画样式<br/>
 * <p>
 * <p>
 * 提供了面向接口编程定制header的功能，去掉了程序中默认的ArrowRefreshHeader
 * 修改为接口BaseRefreshHeader。
 */
class XRecyclerView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : RecyclerView(context, attrs, defStyle) {
    private var listener: Sections? = null
    private var isLoadingData = false
    private var isNoMore = false
    private var mRefreshProgressStyle: Int = ProgressStyle.SysProgress
    private var mLoadingMoreProgressStyle: Int = ProgressStyle.SysProgress
    private var mHeaderViews: SparseArrayCompat<View> = SparseArrayCompat<View>()
    private var mFooterViews: SparseArrayCompat<View> = SparseArrayCompat<View>()
    private var mWrapAdapter: WrapAdapter? = null
    private var mLastY = -1f
    private var DRAG_RATE = 3f
    private var mLoadingListener: LoadingListener? = null
    private var mRefreshHeader: IRefreshHeader? = null
    private var mRefreshFooter: IMoreFooter? = null
    private var pullRefreshEnabled = true
    private var loadingMoreEnabled = true
    private var isEnabledScroll = true

    //adapter没有数据的时候显示,类似于listView的emptyView
    private var mEmptyView: View? = null
    private val mDataObserver: AdapterDataObserver = DataObserver()
    private var appbarState = AppBarStateChangeListener.State.EXPANDED

    companion object {
        //下面的ItemViewType是保留值(ReservedItemViewType),如果用户的adapter与它们重复将会强制抛出异常。不过为了简化,我们检测到重复时对用户的提示是ItemViewType必须小于10000
        const val TYPE_REFRESH_HEADER = 300000 //设置一个很大的数字,尽可能避免和用户的adapter冲突

        const val TYPE_LOADMORE_FOOTER = 300001
        const val HEADER_INIT_INDEX = 300002
        const val FOOTER_INIT_INDEX = 400002
    }

    init {
        if (pullRefreshEnabled) {
            mRefreshHeader = ArrowRefreshHeader(getContext())
            mRefreshHeader.setProgressStyle(mRefreshProgressStyle)
        }
        val moreFooter = LoadingMoreFooter(getContext())
        moreFooter.setProgressStyle(mLoadingMoreProgressStyle)
        mRefreshFooter = moreFooter
        mRefreshFooter.getFooterView().setVisibility(GONE)
    }

    fun setListener(listener: Sections) {
        this.listener = listener
    }

    fun setFootViewText(loading: String, noMore: String) {
        mRefreshFooter.setLoadingHint(loading)
        mRefreshFooter.setNoMoreHint(noMore)
    }

    /**
     * 添加头部view
     */
    fun addHeaderView(view: View) {
        mHeaderViews.put(HEADER_INIT_INDEX + mHeaderViews.size(), view)
        if (mWrapAdapter != null) {
            mWrapAdapter.notifyDataSetChanged()
        }
        requestLayout()
    }

    /**
     * 移除头部view
     */
    fun removeHeaderView(view: View) {
        if (mHeaderViews.size() < 1) return
        val index = mHeaderViews.indexOfValue(view)
        if (index == -1) return
        mHeaderViews.removeAt(index)
        mWrapAdapter?.notifyDataSetChanged()
        requestLayout()
    }

    /**
     * 添加尾部view
     */
    fun addFooterView(view: View) {
        mFooterViews.put(FOOTER_INIT_INDEX + mFooterViews.size(), view)
        if (mWrapAdapter != null) {
            mWrapAdapter.notifyDataSetChanged()
        }
        requestLayout()
    }

    /**
     * 移除尾部view
     */
    fun removeFooterView(view: View) {
        val index = mFooterViews.indexOfValue(view)
        if (index == -1) return
        mFooterViews.removeAt(index)
        mWrapAdapter?.notifyDataSetChanged()
        requestLayout()
    }

    //根据header的ViewType判断是哪个header
    private fun getHeaderViewByType(itemType: Int): View? {
        return if (!isHeaderType(itemType)) {
            null
        } else mHeaderViews[itemType]
    }

    //根据footer的ViewType判断是哪个footer
    private fun getFooterViewByType(itemType: Int): View? {
        return if (!isFooterType(itemType)) {
            null
        } else mFooterViews[itemType]
    }

    //判断一个type是否为HeaderType
    private fun isHeaderType(itemViewType: Int): Boolean {
        return mHeaderViews.size() > 0 && mHeaderViews[itemViewType] != null
    }

    //判断一个type是否为FooterType
    private fun isFooterType(itemViewType: Int): Boolean {
        return mFooterViews.size() > 0 && mFooterViews[itemViewType] != null
    }

    //判断是否是XRecyclerView保留的itemViewType
    private fun isReservedItemViewType(itemViewType: Int): Boolean {
        return itemViewType == TYPE_REFRESH_HEADER || itemViewType == TYPE_LOADMORE_FOOTER || mHeaderViews[itemViewType] != null || mFooterViews[itemViewType] != null
    }

    fun loadMoreComplete() {
        isLoadingData = false
        mRefreshFooter.setState(IMoreFooter.STATE_COMPLETE)
    }

    fun setNoMore(noMore: Boolean) {
        isLoadingData = false
        isNoMore = noMore
        mRefreshFooter.setState(if (isNoMore) IMoreFooter.STATE_NOMORE else IMoreFooter.STATE_COMPLETE)
    }

    fun refresh() {
        if (pullRefreshEnabled && mLoadingListener != null) {
            mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING)
            mLoadingListener.onRefresh()
        }
    }

    /**
     * 增加了是否在刷新,刷新中或者加载更多中
     */
    fun isRefresh(): Boolean {
        return isRefreshing() || isLoadingMore()
    }

    /**
     * 增加了判断是否在刷新的判断
     * 1.上拉刷新中
     */
    fun isRefreshing(): Boolean {
        return mRefreshHeader.isRefreshHreader()
    }

    /**
     * 增加了判断是否在加载更多的判断
     * 1.加载更多中
     */
    fun isLoadingMore(): Boolean {
        //return ((BaseLoadingFooter) mFootView).isLoadingMore();
        return isLoadingData
    }

    fun reset() {
        setNoMore(false)
        loadMoreComplete()
        refreshComplete()
    }

    fun refreshComplete() {
        mRefreshHeader.refreshComplete()
        setNoMore(false)
    }

    fun getRefreshHeader(): IRefreshHeader? {
        return mRefreshHeader
    }

    fun setLoadingMoreFooter(loadingFooter: IMoreFooter) {
        mRefreshFooter = loadingFooter
        mRefreshFooter.getFooterView().setVisibility(GONE)
    }

    fun setRefreshHeader(refreshHeader: IRefreshHeader) {
        mRefreshHeader = refreshHeader
    }

    /**
     * 设置下拉刷新是否可用
     */
    fun setPullRefreshEnabled(enabled: Boolean) {
        pullRefreshEnabled = enabled
    }

    fun isPullRefreshEnabled(): Boolean {
        return pullRefreshEnabled
    }

    /**
     * 设置上拉加载是否可用
     */
    fun setLoadingMoreEnabled(enabled: Boolean) {
        loadingMoreEnabled = enabled
        if (!enabled) {
            mRefreshFooter.setState(IMoreFooter.STATE_COMPLETE)
        }
    }

    fun setRefreshProgressStyle(style: Int) {
        mRefreshProgressStyle = style
        if (mRefreshHeader != null) {
            mRefreshHeader.setProgressStyle(style)
        }
    }

    fun setLoadingMoreProgressStyle(style: Int) {
        mLoadingMoreProgressStyle = style
        mRefreshFooter.setProgressStyle(style)
    }

    fun setArrowImageView(resId: Int) {
        if (mRefreshHeader != null) {
            mRefreshHeader.setArrowImageView(resId)
        }
    }

    fun setEmptyView(emptyView: View?) {
        mEmptyView = emptyView
        mDataObserver.onChanged()
    }

    fun getEmptyView(): View? {
        return mEmptyView
    }

    private var mAdapter: Adapter<*>? = null
    override fun setAdapter(adapter: Adapter<*>?) {
        mAdapter?.unregisterAdapterDataObserver(mDataObserver)
        mAdapter = adapter
        mWrapAdapter = WrapAdapter(adapter)
        super.setAdapter(adapter)
        adapter?.registerAdapterDataObserver(mDataObserver)
        mDataObserver.onChanged()
    }

    override fun getAdapter(): Adapter<*>? {
        return if (mWrapAdapter != null)
            mWrapAdapter.getOriginalAdapter()
        else
            null
    }

    //加载更多是否可用
    fun isLoadingMoreEnabled(): Boolean {
        return loadingMoreEnabled
    }

    //这个包含了头、尾、内容
    fun getItemCount(): Int {
        return if (mWrapAdapter != null) {
            mWrapAdapter.getItemCount()
        } else 0
    }

    fun setEnabledScroll(enabledScroll: Boolean) {
        isEnabledScroll = enabledScroll;
    }

    fun isHeaderFooter(position: Int): Boolean {
        val isHeader: Boolean = mWrapAdapter.isHeader(position)
        val isFooter: Boolean = mWrapAdapter.isFooter(position)
        val isLoadMoreFooter: Boolean = mWrapAdapter.isLoadMoreFooter(position)
        val isRefreshHeader: Boolean = mWrapAdapter.isRefreshHeader(position)
        return isHeader || isFooter || isLoadMoreFooter || isRefreshHeader
    }

    // 获取头的个数 不包含刷新头
    fun getHeadersCount(): Int {
        return mHeaderViews.size()
    }

    // 获取尾的个数 不包含加载更多
    fun getFootersCount(): Int {
        return mFooterViews.size()
    }

    override fun setLayoutManager(layout: LayoutManager?) {
        super.setLayoutManager(layout)
        if (mWrapAdapter != null) {
            if (layout is GridLayoutManager) {
                layout.spanSizeLookup = object : SpanSizeLookup() {
                    override fun getSpanSize(position: Int): Int {
                        return if (isHeaderFooter(position)) layout.spanCount else 1
                    }
                }
            }
        }
    }

    override fun onScreenStateChanged(state: Int) {
        super.onScreenStateChanged(state)
        if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingData && loadingMoreEnabled) {
            val layoutManager = layoutManager
            val lastVisibleItemPosition: Int
            if (layoutManager is GridLayoutManager) {
                lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
            } else if (layoutManager is StaggeredGridLayoutManager) {
                val into = IntArray(layoutManager.spanCount)
                layoutManager.findLastVisibleItemPositions(into)
                lastVisibleItemPosition = findMax(into)
            } else {
                lastVisibleItemPosition =
                    (layoutManager as LinearLayoutManager?)!!.findLastVisibleItemPosition()
            }
            if (layoutManager.getChildCount() > 0
                && lastVisibleItemPosition >= layoutManager.getItemCount() - 1
                /* && layoutManager.getItemCount() > layoutManager.getChildCount() */ //解决屏幕不满足一屏无法加载更多的问题
                && !isNoMore && isEnabledScroll && mRefreshHeader.getState() < IRefreshHeader.STATE_REFRESHING
            ) {
                isLoadingData = true;
                if (mRefreshFooter instanceof IMoreFooter) {
                    mRefreshFooter.setState(LoadingMoreFooter.STATE_LOADING);
                } else {
                    mRefreshFooter.getFooterView().setVisibility(View.VISIBLE);
                }
                mLoadingListener.onLoadMore();
            }
        }
    }

    var y1 = 0f
    var y2 = 0f

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        if (mLastY == -1f) {
            mLastY = ev.rawY
        }
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                mLastY = ev.rawY
                y1 = ev.y
            }
            MotionEvent.ACTION_MOVE -> {
                val deltaY: Float = ev.rawY - mLastY
                mLastY = ev.rawY
                if (isOnTop() && pullRefreshEnabled && isEnabledScroll && appbarState === AppBarStateChangeListener.State.EXPANDED) {
                    mRefreshHeader.onMove(deltaY / DRAG_RATE)
                    if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
                        return false
                    }
                }
            }
            else -> {
                mLastY = -1f // reset

                //解决禁止下拉刷新功能，只有加载更多的时候，下拉刷新动作也会触发加载更多的问题
                y2 = ev.y
                val isTop: Boolean = isOnTop()
                if (isTop && y2 - y1 > 50 && !pullRefreshEnabled) {
                    return false
                }
                if (isTop && pullRefreshEnabled && isEnabledScroll && appbarState === AppBarStateChangeListener.State.EXPANDED) {
                    if (mRefreshHeader.releaseAction()) {
                        if (mLoadingListener != null) {
                            mLoadingListener.onRefresh()
                        }
                    }
                }
            }
        }
        return super.onTouchEvent(ev)
    }

    private fun findMax(lastPositions: IntArray): Int {
        var max = lastPositions[0]
        for (value in lastPositions) {
            if (value > max) {
                max = value
            }
        }
        return max
    }

    private fun isOnTop(): Boolean {
        return mRefreshHeader.getHeaderView().getParent() != null
    }

    private class DataObserver : AdapterDataObserver() {
        override fun onChanged() {
            if (mWrapAdapter != null) {
                mWrapAdapter.notifyDataSetChanged()
            }
            if (mWrapAdapter != null && mEmptyView != null) {
                var emptyCount: Int = 1 + mWrapAdapter.getHeadersCount()
                if (loadingMoreEnabled) {
                    emptyCount++
                }
                if (mWrapAdapter.getItemCount() === emptyCount) {
                    mEmptyView.setVisibility(VISIBLE)
                    this@XRecyclerView.setVisibility(GONE)
                } else {
                    mEmptyView.setVisibility(GONE)
                    this@XRecyclerView.setVisibility(VISIBLE)
                }
            }
        }

        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount)
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount)
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload)
        }

        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount)
        }

        override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
            mWrapAdapter.notifyItemMoved(fromPosition, toPosition)
        }
    }

    class WrapAdapter(val originalAdapter: Adapter<*>?) :
        Adapter<ViewHolder>() {

        fun isHeader(position: Int): Boolean {
            return position >= 1 && position < mHeaderViews.size() + 1
        }

        fun isFooter(position: Int): Boolean {
            //Log.i("test", "position>>>>:" + position + " headerscount:" + getHeadersCount() + " contentscount:" + getContentsCount() + " itemcount:" + getItemCount());
            val adjLen = if (loadingMoreEnabled) 2 else 1
            return position <= itemCount - adjLen && position > itemCount - adjLen - footersCount
        }

        fun isLoadMoreFooter(position: Int): Boolean {
            return if (loadingMoreEnabled) {
                position == itemCount - 1
            } else {
                false
            }
        }

        fun isRefreshHeader(position: Int): Boolean {
            return position == 0
        }

        val headersCount: Int
            get() = mHeaderViews.size()
        val footersCount: Int
            get() = mFooterViews.size()
        val contentsCount: Int
            get() = originalAdapter!!.itemCount

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            if (viewType == TYPE_REFRESH_HEADER) {
                return SimpleViewHolder(mRefreshHeader.getHeaderView())
            } else if (isHeaderType(viewType)) {
                return SimpleViewHolder(getHeaderViewByType(viewType))
            } else if (isFooterType(viewType)) {
                return SimpleViewHolder(getFooterViewByType(viewType))
            } else if (viewType == TYPE_LOADMORE_FOOTER) {
                return SimpleViewHolder(mRefreshFooter.getFooterView())
            }
            return originalAdapter!!.onCreateViewHolder(parent, viewType)
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            if (isHeader(position) || isRefreshHeader(position)) {
                return
            }
            val adjPosition = position - (headersCount + 1)
            val adapterCount: Int
            if (originalAdapter != null) {
                adapterCount = originalAdapter.itemCount
                if (adjPosition < adapterCount) {
                    originalAdapter.onBindViewHolder(holder, adjPosition)
                }
            }
        }

        // some times we need to override this
        override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: List<Any>) {
            if (isHeader(position) || isRefreshHeader(position)) {
                return
            }
            val adjPosition = position - (headersCount + 1)
            val adapterCount: Int
            if (originalAdapter != null) {
                adapterCount = originalAdapter.itemCount
                if (adjPosition < adapterCount) {
                    if (payloads.isEmpty()) {
                        originalAdapter.onBindViewHolder(holder, adjPosition)
                    } else {
                        originalAdapter.onBindViewHolder(holder, adjPosition, payloads)
                    }
                }
            }
        }

        override fun getItemCount(): Int {
            val adjLen = if (loadingMoreEnabled) 2 else 1
            return if (originalAdapter != null) {
                headersCount + originalAdapter.itemCount + adjLen + footersCount
            } else {
                headersCount + adjLen + footersCount
            }
        }

        override fun getItemViewType(position: Int): Int {
            var position = position
            val adjPosition = position - (headersCount + 1)
            if (isRefreshHeader(position)) {
                return TYPE_REFRESH_HEADER
            }
            if (isHeader(position)) {
                position = position - 1
                return mHeaderViews.keyAt(position)
            } else if (isFooter(position)) {
                //Log.i("test", "position:" + position + " headerscount:" + getHeadersCount() + " contentscount:" + getContentsCount() + " itemCount:" + getItemCount());
                position = position - headersCount - contentsCount - 1
                return mFooterViews.keyAt(position)
            }
            if (isLoadMoreFooter(position)) {
                return TYPE_LOADMORE_FOOTER
            }
            val adapterCount: Int
            if (originalAdapter != null) {
                adapterCount = originalAdapter.itemCount
                if (adjPosition < adapterCount) {
                    val type = originalAdapter.getItemViewType(adjPosition)
                    check(!isReservedItemViewType(type)) { "XRecyclerView require itemViewType in adapter should be less than 10000 " }
                    return type
                }
            }
            return 0
        }

        override fun getItemId(position: Int): Long {
            if (originalAdapter != null && position >= headersCount + 1) {
                val adjPosition = position - (headersCount + 1)
                if (adjPosition < originalAdapter.itemCount) {
                    return originalAdapter.getItemId(adjPosition)
                }
            }
            return -1
        }

        override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
            super.onAttachedToRecyclerView(recyclerView)
            val manager = recyclerView.layoutManager
            if (manager is GridLayoutManager) {
                val gridManager = manager
                gridManager.spanSizeLookup = object : SpanSizeLookup() {
                    override fun getSpanSize(position: Int): Int {
                        val isLister =
                            listener != null && listener.isSections(
                                position,
                                isHeaderFooter(position)
                            )
                        return if (isHeaderFooter(position) || isLister) gridManager.spanCount else 1
                    }
                }
            }
            originalAdapter!!.onAttachedToRecyclerView(recyclerView)
        }

        override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
            originalAdapter!!.onDetachedFromRecyclerView(recyclerView)
        }

        override fun onViewAttachedToWindow(holder: ViewHolder) {
            super.onViewAttachedToWindow(holder)
            val lp = holder.itemView.layoutParams
            if (lp != null && lp is StaggeredGridLayoutManager.LayoutParams
                && (isHeader(holder.layoutPosition) || isRefreshHeader(holder.layoutPosition) || isLoadMoreFooter(
                    holder.layoutPosition
                ))
            ) {
                lp.isFullSpan = true
            }
            originalAdapter!!.onViewAttachedToWindow(holder)
        }

        override fun onViewDetachedFromWindow(holder: ViewHolder) {
            originalAdapter!!.onViewDetachedFromWindow(holder)
        }

        override fun onViewRecycled(holder: ViewHolder) {
            originalAdapter!!.onViewRecycled(holder)
        }

        override fun onFailedToRecycleView(holder: ViewHolder): Boolean {
            return originalAdapter!!.onFailedToRecycleView(holder)
        }

        override fun unregisterAdapterDataObserver(observer: AdapterDataObserver) {
            originalAdapter!!.unregisterAdapterDataObserver(observer)
        }

        override fun registerAdapterDataObserver(observer: AdapterDataObserver) {
            originalAdapter!!.registerAdapterDataObserver(observer)
        }

        private inner class SimpleViewHolder(itemView: View?) : BH(itemView!!)
    }

    fun setLoadingListener(listener: LoadingListener) {
        mLoadingListener = listener
    }

    fun setLoadingListener(onRefresh: () -> Unit, onLoadMore: () -> Unit) {
        mLoadingListener = object : LoadingListener {
            override fun onRefresh() {
                onRefresh.invoke()
            }

            override fun onLoadMore() {
                onLoadMore.invoke()
            }
        }
    }

    interface LoadingListener {
        fun onRefresh()
        fun onLoadMore()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        //解决和CollapsingToolbarLayout冲突的问题
        var appBarLayout: AppBarLayout? = null
        var p = parent
        while (p != null) {
            if (p is CoordinatorLayout) {
                break
            }
            p = p.parent
        }
        if (p is CoordinatorLayout) {
            val coordinatorLayout = p
            val childCount = coordinatorLayout.childCount
            for (i in childCount - 1 downTo 0) {
                val child = coordinatorLayout.getChildAt(i)
                if (child is AppBarLayout) {
                    appBarLayout = child
                    break
                }
            }
            appBarLayout?.addOnOffsetChangedListener(object : AppBarStateChangeListener() {
                override fun onStateChanged(appBarLayout: AppBarLayout, state: State) {
                    appbarState = state
                }
            })
        }
    }
    interface Sections {
        fun isSections(position: Int, isHeadOrRefresh: Boolean): Boolean
    }
}